package com.xisoft.generator.service.impl;

import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.xisoft.base.config.DataSrcConfig;
import com.xisoft.base.service.XfServiceImpl;
import com.xisoft.common.io.FileUtilbc;
import com.xisoft.common.pubEnv.CollectionUtil;
import com.xisoft.common.pubEnv.PubEnvUtil;
import com.xisoft.common.pubEnv.StringUtil;
import com.xisoft.generator.config.TemplateConfig;
import com.xisoft.generator.entity.BaseModel;
import com.xisoft.generator.handle.*;
import com.xisoft.generator.mapper.SysGeneratorMapper;
import com.xisoft.generator.service.ISysGeneratorService;
import com.xisoft.generator.utils.PageUtils;
import com.xisoft.generator.utils.Query;
import com.xisoft.generator.utils.ResultEntity;
import com.xisoft.utils.SpringHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * *
 * Created with Description:
 *
 * @fileRelativePath: SysGeneratorService.java
 * @Date: Created on 2022/7/25  11:06  <br>
 * @author: LiBencheng <br>
 * @version: 1.0 <br>
 */
@Service ("SysGeneratorServiceImpl")
public class SysGeneratorServiceImpl extends XfServiceImpl implements ISysGeneratorService
{
    @Autowired
    TemplateConfig templateConfig;
    @Autowired
    DataSrcConfig dataSrcConfig;
    @Autowired
    private SysGeneratorMapper genMapper;

    @Override public void create(String table)
    {
        try
        {
            new HashSet<>(Arrays.asList(table.toString().split(PubEnvUtil.COMMA)))
                    .forEach(tableName ->
                             {
                                 BaseModel model = new BaseModel();
                                 model.templateConfig = this.templateConfig;
                                 model.base_path = this.templateConfig.BASE_PATH;
                                 model.tablename = tableName.trim();
                                 model.basePackageName = this.templateConfig.BASEPACKAGENAME;
                                 model.author = this.templateConfig.AUTHOR;
                                 HandlerChain handlerChain = new HandlerChainImp();
                                 handlerChain.addHandler(new CheckHandler());
                                 handlerChain.addHandler(new DBHandler());
                                 handlerChain.addHandler(new TempldateHandler());

                                 handlerChain.handle(model);
                             });
        }
        catch (RuntimeException e)
        {
            System.out.println("代码生产失败，异常；" + e.getMessage());
            throw new RuntimeException("代码生产失败，异常；" + e.getMessage());
        }


    }

    @Override public byte[] generatorCode( ) throws IOException
    {
        BufferedInputStream bis = null;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
        List< File > sourceFiles = FileUtilbc.listFile(this.templateConfig.BASE_PATH + File.separator + "src");
        byte[] buffer = new byte[4096];

        for (int i = 0; i < sourceFiles.size(); ++i)
        {
            String fileName = ((File) sourceFiles.get(i)).getPath()
                                                         .replace(this.templateConfig.BASE_PATH.replace("/", "\\"), "");
            ZipEntry zipEntry = new ZipEntry(fileName);
            zipOutputStream.putNextEntry(zipEntry);
            bis = new BufferedInputStream(new FileInputStream((File) sourceFiles.get(i)), 4096);
            boolean var9 = false;

            int read;
            while ((read = bis.read(buffer)) != -1)
            { zipOutputStream.write(buffer, 0, read); }
        }

        buffer = outputStream.toByteArray();
        zipOutputStream.flush();
        outputStream.flush();
        zipOutputStream.close();
        outputStream.close();
        return buffer;
    }

    @Override public String queryList(Query query) throws Exception
    {
        int total = 0;
        String group = ((DataSrcConfig) SpringHelper.getBean(DataSrcConfig.class)).group;
        List< Entity > tableList = new LinkedList();
        if (PubEnvUtil.equals("orcl", group))
        {
            total = Integer.parseInt(StringUtil.valueOfZero(genMapper.getConTotal(queryListContByOrcl(query, group))
                                                                     .get("total")));
            tableList = genMapper.getTableName(String.valueOf(queryListByOrcl(query, group)));
        }

        if (PubEnvUtil.equals("mysql", group))
        {
            total = Integer.parseInt(StringUtil.valueOfZero(genMapper.getConTotal(queryListContByMysql(query, group))
                                                                     .get("total")));
            tableList = genMapper.getTableName(String.valueOf(queryListByMysql(query, group)));
        }

        PageUtils page = new PageUtils((List) tableList, total, query.getLimit(), query.getPage());
        ResultEntity rest = ResultEntity.ok();
        rest.put("page", CollectionUtil.transBean2Map(page));
        rest.put("data", CollectionUtil.transBean2Map(page));
        return CollectionUtil.map2Josn(rest);
    }

    public String queryListContByOrcl(Query query, String group) throws Exception
    {
        StringBuilder sql = new StringBuilder();
        sql.append(" SELECT");
        sql.append(" COUNT(dt.table_name) AS \"total\"");
        sql.append(" FROM");
        sql.append(" user_tables dt");
        sql.append(" LEFT JOIN user_tab_comments   dtc ON dtc.table_name = dt.table_name");
        sql.append(" LEFT JOIN user_objects        uo ON uo.object_name = dt.table_name");
        sql.append(" WHERE");
        sql.append(" uo.object_type IN (  'TABLE', 'VIEW' )");
        if (!PubEnvUtil.isEmpty(new String[]{StringUtil.valueOf(query.get("tableName"))}))
        {
            String tableName = query.get("tableName").toString().toUpperCase().trim();
            sql.append(" AND ( dt.table_name LIKE '%").append(tableName.toLowerCase()).append("%'");
            sql.append("  OR dtc.comments LIKE '%").append(tableName).append("%')");
        }

        return String.valueOf(sql);
        // Integer i = Integer.parseInt(StringUtil.valueOfZero(genMapper.getConTotal(String.valueOf(sql)).get
        // ("total")));
        // return ((Entity) Db.use(group).query(String.valueOf(sql)).get(0)).getInt("total");
    }

    public String queryListByOrcl(Query query, String group) throws Exception
    {
        StringBuilder sql = new StringBuilder();
        sql.append(" SELECT");
        sql.append(" *");
        sql.append(" FROM");
        sql.append(" (");
        sql.append(" SELECT");
        sql.append(" dt.table_name  AS \"engine\",");
        sql.append(" dtc.comments   AS \"tablename\",");
        sql.append(" MAX(uo.last_ddl_time) AS \"createtime\",");
        sql.append(" uo.object_type  AS \"tabletype\",");
        sql.append(" ROWNUM   AS rn");
        sql.append(" FROM");
        sql.append(" user_tables dt");
        sql.append(" LEFT JOIN user_tab_comments   dtc ON dtc.table_name = dt.table_name");
        sql.append(" LEFT JOIN user_objects        uo ON uo.object_name = dt.table_name");
        sql.append(" WHERE");
        sql.append(" uo.object_type IN (  'TABLE', 'VIEW' )");
        sql.append(" AND 1 = 1");
        if (!PubEnvUtil.isEmpty(new String[]{StringUtil.valueOf(query.get("tableName"))}))
        {
            String tableName = query.get("tableName").toString().toUpperCase().trim();
            sql.append(" AND ( dt.table_name LIKE '%").append(tableName.toLowerCase()).append("%'");
            sql.append("  OR dtc.table_name LIKE '%").append(tableName).append("%')");
        }

        sql.append(" GROUP BY");
        sql.append(" ROWNUM,");
        sql.append(" dt.table_name,");
        sql.append(" dtc.comments,");
        sql.append(" uo.object_type");
        sql.append(" ORDER BY");
        sql.append(" dt.table_name,dtc.comments ");
        sql.append(" )");
        sql.append(" WHERE");
        sql.append(" rn >= ")
           .append(Math.multiplyExact(Integer.valueOf(String.valueOf(query.get("limit"))),
                                      Math.subtractExact(Integer.valueOf(String.valueOf(query.get("page"))), 1)))
           .append("  AND rn <=  ")
           .append(Math.multiplyExact(Integer.valueOf(String.valueOf(query.get("limit"))),
                                      Integer.valueOf(String.valueOf(query.get("page")))))
           .append(" ");

        return String.valueOf(sql);
        // List< Map > tableName = genMapper.getTableName(String.valueOf(sql));
        // return Db.use(group).query(String.valueOf(sql));
    }

    public String queryListContByMysql(Query query, String group) throws Exception
    {
        StringBuilder sql = new StringBuilder();
        sql.append(" SELECT ");
        sql.append("  COUNT(table_name) AS \"total\"");
        sql.append("  FROM information_schema.tables");
        sql.append("  WHERE table_schema='");
        sql.append(((DataSrcConfig) SpringHelper.getBean(DataSrcConfig.class)).user);
        sql.append("'");
        if (!PubEnvUtil.isEmpty(new String[]{StringUtil.valueOf(query.get("tableName"))}))
        {
            String tableName = query.get("tableName").toString().toUpperCase().trim();
            sql.append(" AND ( table_name LIKE '%").append(tableName.toLowerCase()).append("%'");
            sql.append("  OR table_name LIKE '%").append(tableName).append("%' ");
        }

        return String.valueOf(sql);
        // return ((Entity) Db.use(group).query(String.valueOf(sql)).get(0)).getInt("total");
    }

    public String queryListByMysql(Query query, String group) throws Exception
    {
        LinkedList< Object > pramList = new LinkedList();
        StringBuilder sql = new StringBuilder();
        sql.append(" SELECT ");
        sql.append("  table_name \"tableName\", engine,");
        sql.append("  table_comment \"tableComment\",");
        sql.append("  create_time \"createTime\" ");
        sql.append("  FROM information_schema.tables");
        sql.append("  WHERE table_schema='");
        sql.append(((DataSrcConfig) SpringHelper.getBean(DataSrcConfig.class)).user);
        sql.append("'");
        if (!PubEnvUtil.isEmpty(new String[]{StringUtil.valueOf(query.get("tableName"))}))
        {
            String tableName = query.get("tableName").toString().toUpperCase().trim();

            sql.append(" AND ( table_name LIKE '%").append(tableName.toLowerCase()).append("%'");
            sql.append("  OR table_name LIKE '%").append(tableName).append("%' ");
        }

        return String.valueOf(sql);
        // return Db.use(group).query(String.valueOf(sql), pramList.toArray());
    }

    public PageUtils queryListByDic(Query query) throws Exception
    {
        String sql = "SELECT sdt_table_en_name AS tablename,sdt_table_zh_name AS engine,sdt_system_name AS " +
                "tablecomment,sdt_table_type AS tabletype FROM sys_dic_table WHERE 1=?";
        LinkedList< Object > pramList = new LinkedList();
        pramList.add("1");
        if (!PubEnvUtil.isEmptyObj(query.get("tableName")))
        {
            sql = sql + " AND sdt_table_en_name =?";
            pramList.add(query.get("tableName").toString().toUpperCase());
        }

        List< Entity > list = Db.use().query(sql, pramList.toArray());
        int total = null == list ? 0 : list.size();
        return new PageUtils(list, total, query.getLimit(), query.getPage());
    }

    @Override public String getColumns(String tableName) throws Exception
    {
        String group = ((DataSrcConfig) SpringHelper.getBean(DataSrcConfig.class)).group;
        List< Entity > list = new LinkedList();
        if (PubEnvUtil.equals("orcl", group))
        { list = genMapper.getColumns(queryColumnByOrcl(tableName, group)); }

        if (PubEnvUtil.equals("mysql", group))
        { list = genMapper.getColumns(queryColumnByMysql(tableName, group)); }

        PageUtils page = new PageUtils((List) list, PubEnvUtil.getObjSize(list), 0, 0);
        ResultEntity ok = ResultEntity.ok();
        ok.put("page", CollectionUtil.transBean2Map(page));
        ok.put("data", CollectionUtil.transBean2Map(page));
        return CollectionUtil.map2Josn(ok);
    }

    @Override public List< Entity > dictionary(String tableName) throws Exception
    {
        String group = ((DataSrcConfig) SpringHelper.getBean(DataSrcConfig.class)).group;
        List< Entity > list = new LinkedList();
        if (PubEnvUtil.equals("orcl", group))
        { list = genMapper.getColumns(queryColumnByOrcl(tableName, group)); }

        if (PubEnvUtil.equals("mysql", group))
        { list = genMapper.getColumns(queryColumnByMysql(tableName, group)); }

        // List< Entity > list = new LinkedList();
        // if (PubEnvUtil.equals("orcl", group))
        // { list = this.queryColumnByOrcl(tableName, group); }
        //
        // if (PubEnvUtil.equals("mysql", group))
        // { list = this.queryColumnByMysql(tableName, group); }

        return list;
        // return CollectionUtil.map2Josn((List) list);
    }

    public String queryColumnByOrcl(final String tableName, String group) throws Exception
    {
        StringBuilder sql = new StringBuilder();
        sql.append(" SELECT");
        sql.append(" user_tab_columns.table_name       AS \"table_code\",/*表名*/");
        sql.append(" user_tab_comments.comments        AS \"table_name\",/*表备注*/");
        sql.append(" user_tab_columns.column_name      AS \"col_code\",/*列名*/");
        sql.append(" user_col_comments.comments        AS \"col_name\",/*列备注*/");
        sql.append(" user_tab_columns.data_type        AS \"col_type\",/*类型*/");
        sql.append(" decode(user_tab_columns.nullable, 'N', '1', '0') AS \"nullable\",/*是否可空*/");
        sql.append(" user_tab_columns.data_length      AS \"data_length\",/*数据长度*/");
        sql.append(" user_tab_columns.data_precision   AS \"data_precision\",/*数据精度*/");
        sql.append(" decode(pk.column_name, NULL, '0', '1') AS \"pk\"/*是否主键*/");
        sql.append(" FROM user_tab_columns    user_tab_columns");
        sql.append(" LEFT JOIN user_tab_comments   user_tab_comments ");
        sql.append(" ON user_tab_columns.table_name = user_tab_comments.table_name");
        sql.append(" JOIN user_col_comments   user_col_comments");
        sql.append(" ON user_col_comments.table_name = user_tab_columns .table_name");
        sql.append(" AND user_col_comments.column_name = user_tab_columns.column_name");
        sql.append(" LEFT JOIN (");
        sql.append(" SELECT");
        sql.append(" user_cons_columns.table_name,");
        sql.append(" user_cons_columns.column_name");
        sql.append(" FROM");
        sql.append(" user_cons_columns user_cons_columns,");
        sql.append(" user_constraints user_constraints");
        sql.append(" WHERE");
        sql.append(" user_cons_columns.constraint_name = user_constraints.constraint_name");
        sql.append(" AND user_constraints.constraint_type = 'P'");
        sql.append(" AND (user_constraints.table_name = '").append(tableName.toUpperCase());
        sql.append("'OR user_constraints.table_name = '").append(tableName.toLowerCase());
        sql.append("')) pk ON pk.column_name = user_tab_columns.column_name");
        sql.append(" WHERE");
        sql.append(" (user_tab_columns.table_name = '").append(tableName.toUpperCase());
        sql.append("'OR user_tab_columns.table_name = '").append(tableName.toLowerCase());
        sql.append("') ORDER BY user_tab_columns.column_id ASC");

        return sql.toString();
        // return Db.use(group).query(String.valueOf(sql), (new LinkedList()
        // {
        //     {
        //         this.add(tableName.toUpperCase());
        //         this.add(tableName.toLowerCase());
        //         this.add(tableName.toUpperCase());
        //         this.add(tableName.toLowerCase());
        //     }
        // }).toArray());
    }

    public String queryColumnByMysql(final String tableName, String group) throws Exception
    {
        StringBuilder sql = new StringBuilder();
        sql.append(" SELECT");
        sql.append(" table_name      AS \"table_code\",/*表名*/");
        sql.append(" column_name     AS \"col_code\",/*字段名称*/");
        sql.append(" column_comment  AS \"col_name\",/* 字段说明*/");
        sql.append(" column_type     AS \"col_type\",/*字段类型长度*/");
        sql.append(" is_nullable     AS \"nullable\",/*是否可空*/");
        sql.append(" if(extra = \"auto_increment\", concat(column_key, \"(\", ");
        sql.append(" if(extra = \"auto_increment\", \"自增\", extra), \")\"),");
        sql.append("  column_key)) as \"pk\"/*是否主键*/");
        sql.append(" FROM information_schema.columns");
        sql.append(" /*数据库名：jn_power 表名 rpt_cap_hour_ammeter_201810*/");
        // sql.append(" WHERE  table_schema = ? AND table_name = ? ;");
        sql.append(" WHERE (table_name = '").append(tableName.toUpperCase()).append("'");
        sql.append(" OR table_name = '").append(tableName.toLowerCase()).append("' )");
        sql.append(" ");

        return sql.toString();
        // return Db.use(group).query(String.valueOf(sql), (new LinkedList()
        // {
        //     {
        //         // this.add(((DBConfig) SpringHelper.getBean(DBConfig.class)).table_schema);
        //         this.add(tableName);
        //     }
        // }).toArray());
    }
}
